package com.example.moniter;

import java.beans.ConstructorProperties;
import java.util.Iterator;
import java.util.List;
import javax.annotation.PostConstruct;

import com.example.annotation.ShardRabbitListener;
import com.example.config.ShardRabbitListenerConfigUtils;
import com.example.lock.ShardRabbitLockManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.consul.discovery.ConsulDiscoveryClient;
import org.springframework.stereotype.Component;

@Component
public class ShardRabbitMonitor implements BeanFactoryAware {
    private static final Logger log = LoggerFactory.getLogger(ShardRabbitMonitor.class);
    @Value("${spring.application.name}")
    private String serviceName;
    @Autowired
    private ConsulDiscoveryClient discoveryClient;
    private BeanFactory beanFactory;
    public static volatile boolean isReady = false;

    public ShardRabbitMonitor() {
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @PostConstruct
    private void init() {
        ShardRabbitMonitor.ShardRabbitMonitorThread shardRabbitMonitorThread = new ShardRabbitMonitor.ShardRabbitMonitorThread(this.serviceName, this.discoveryClient, this.beanFactory);
        shardRabbitMonitorThread.start();
        log.info("shardRabbitMonitorThread is started");
    }

    private static class ShardRabbitMonitorThread extends Thread {
        private static final Logger log = LoggerFactory.getLogger(ShardRabbitMonitor.ShardRabbitMonitorThread.class);
        private String serviceName;
        private ConsulDiscoveryClient discoveryClient;
        private BeanFactory beanFactory;

        public void run() {
            while(true) {
                try {
                    this.freshLocks();
                    Thread.sleep(3000L);
                    if (ShardRabbitListenerConfigUtils.initDone) {
                        if (!ShardRabbitMonitor.isReady) {
                            this.checkServiceReady();
                        } else {
                            this.monitor();
                        }
                    }
                } catch (Exception var2) {
                    log.error("", var2);
                }
            }
        }

        private void checkServiceReady() {
            List<ServiceInstance> instanceList = this.discoveryClient.getInstances(this.serviceName);
            int instanceSize = instanceList.size();
            log.info("discoveryClient.getInstances instanceSize:{}", instanceSize);
            ShardRabbitListenerManager shardRabbitListenerManager = (ShardRabbitListenerManager)this.beanFactory.getBean(ShardRabbitListenerConfigUtils.RABBIT_LISTENER_MANAGER_BEAN_NAME, ShardRabbitListenerManager.class);
            List<ShardRabbitListener> shardRabbitListeners = shardRabbitListenerManager.getAllShardRabbitListeners();
            log.info("shardRabbitListeners.size:{}", shardRabbitListeners.size());
            if (shardRabbitListeners.size() > 0) {
                boolean allReady = true;
                Iterator var6 = shardRabbitListeners.iterator();

                while(var6.hasNext()) {
                    ShardRabbitListener shardRabbitListener = (ShardRabbitListener)var6.next();
                    String shardSizeStr = (String)shardRabbitListenerManager.resolveExpression(shardRabbitListener.shardSize());
                    String queueName = (String)shardRabbitListenerManager.resolveExpression(shardRabbitListener.queueNamePrefix());
                    int shardSize = Integer.parseInt(shardSizeStr);
                    log.info("queueName:{},shardSizeStr:{}", queueName, shardSizeStr);
                    if (instanceSize < shardSize) {
                        allReady = false;
                        break;
                    }
                }

                if (allReady) {
                    ShardRabbitMonitor.isReady = true;
                    log.info("all service is ready, start to take lock, service name:{}", this.serviceName);
                }

            }
        }

        private void monitor() {
            ShardRabbitLockManager shardRabbitLockManager = this.beanFactory.getBean(ShardRabbitListenerConfigUtils.RABBIT_LISTENER_LOCK_MANAGER_BEAN_NAME, ShardRabbitLockManager.class);
            List<ServiceInstance> instanceList = this.discoveryClient.getInstances(this.serviceName);
            int instanceSize = instanceList.size();
            shardRabbitLockManager.checkLock(instanceSize);
            shardRabbitLockManager.tryAllLock(this.serviceName, instanceSize);
        }

        private void freshLocks() {
            ShardRabbitLockManager shardRabbitLockManager = (ShardRabbitLockManager)this.beanFactory.getBean(ShardRabbitListenerConfigUtils.RABBIT_LISTENER_LOCK_MANAGER_BEAN_NAME, ShardRabbitLockManager.class);
            shardRabbitLockManager.fresh();
        }

        @ConstructorProperties({"serviceName", "discoveryClient", "beanFactory"})
        public ShardRabbitMonitorThread(String serviceName, ConsulDiscoveryClient discoveryClient, BeanFactory beanFactory) {
            this.serviceName = serviceName;
            this.discoveryClient = discoveryClient;
            this.beanFactory = beanFactory;
        }

        public ShardRabbitMonitorThread() {
        }
    }
}